home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Development / TinyGL / ami / content / ad709 / tinygl / src / light.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-15  |  7.3 KB  |  367 lines

  1. /*$T light.c GC 1.137 08/09/02 17:47:18 */
  2.  
  3. /*$6
  4.  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5.  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  6.  */
  7.  
  8. #include "zgl.h"
  9. #include "msghandling.h"
  10.  
  11. /* */
  12.  
  13. void glopMaterial(GLContext *c, GLParam *p) {
  14.     int            mode = p[1].i;
  15.     int            type = p[2].i;
  16.     float        *v = &p[3].f;
  17.     int            i;
  18.     GLMaterial    *m;
  19.     /*~~~~~~~~~~~~~~~~~~~~~~*/
  20.  
  21.     if(mode == GL_FRONT_AND_BACK) {
  22.         p[1].i = GL_FRONT;
  23.         glopMaterial(c, p);
  24.         mode = GL_BACK;
  25.     }
  26.  
  27.     if(mode == GL_FRONT) {
  28.         m = &c->materials[0];
  29.     }
  30.     else {
  31.         m = &c->materials[1];
  32.     }
  33.  
  34.     switch(type) {
  35.     case GL_EMISSION:
  36.         for(i = 0; i < 4; i++) {
  37.             m->emission.v[i] = v[i];
  38.         }
  39.         break;
  40.     case GL_AMBIENT:
  41.         for(i = 0; i < 4; i++) {
  42.             m->ambient.v[i] = v[i];
  43.         }
  44.         break;
  45.     case GL_DIFFUSE:
  46.         for(i = 0; i < 4; i++) {
  47.             m->diffuse.v[i] = v[i];
  48.         }
  49.         break;
  50.     case GL_SPECULAR:
  51.         for(i = 0; i < 4; i++) {
  52.             m->specular.v[i] = v[i];
  53.         }
  54.         break;
  55.     case GL_SHININESS:
  56.         m->shininess = v[0];
  57.         m->shininess_i = (v[0] / 128.0f) * SPECULAR_BUFFER_RESOLUTION;
  58.         break;
  59.     case GL_AMBIENT_AND_DIFFUSE:
  60.         for(i = 0; i < 4; i++) {
  61.             m->diffuse.v[i] = v[i];
  62.         }
  63.  
  64.         for(i = 0; i < 4; i++) {
  65.             m->ambient.v[i] = v[i];
  66.         }
  67.         break;
  68.     default:
  69.         assert(0);
  70.     }
  71. }
  72.  
  73. /* */
  74. void glopColorMaterial(GLContext *c, GLParam *p) {
  75.     int mode = p[1].i;
  76.     int type = p[2].i;
  77.  
  78.     c->current_color_material_mode = mode;
  79.     c->current_color_material_type = type;
  80. }
  81.  
  82. /* */
  83. void glopLight(GLContext *c, GLParam *p) {
  84.     int        light = p[1].i;
  85.     int        type = p[2].i;
  86.     V4        v;
  87.     GLLight *l;
  88.     int        i;
  89.  
  90.     assert(light >= GL_LIGHT0 && light < GL_LIGHT0 + MAX_LIGHTS);
  91.  
  92.     l = &c->lights[light - GL_LIGHT0];
  93.  
  94.     for(i = 0; i < 4; i++) {
  95.         v.v[i] = p[3 + i].f;
  96.     }
  97.  
  98.     switch(type) {
  99.     case GL_AMBIENT:
  100.         l->ambient = v;
  101.         break;
  102.     case GL_DIFFUSE:
  103.         l->diffuse = v;
  104.         break;
  105.     case GL_SPECULAR:
  106.         l->specular = v;
  107.         break;
  108.     case GL_POSITION: {
  109.             V4    pos;
  110.             gl_M4_MulV4(&pos, c->matrix_stack_ptr[0], &v);
  111.  
  112.             l->position = pos;
  113.  
  114.             if(l->position.v[3] == 0) {
  115.                 l->norm_position.X = pos.X;
  116.                 l->norm_position.Y = pos.Y;
  117.                 l->norm_position.Z = pos.Z;
  118.  
  119.                 gl_V3_Norm(&l->norm_position);
  120.             }
  121.         }
  122.         break;
  123.     case GL_SPOT_DIRECTION:
  124.         for(i = 0; i < 3; i++) {
  125.             l->spot_direction.v[i] = v.v[i];
  126.             l->norm_spot_direction.v[i] = v.v[i];
  127.         }
  128.  
  129.         gl_V3_Norm(&l->norm_spot_direction);
  130.         break;
  131.     case GL_SPOT_EXPONENT:
  132.         l->spot_exponent = v.v[0];
  133.         break;
  134.     case GL_SPOT_CUTOFF: {
  135.             float    a = v.v[0];
  136.             assert(a == 180 || (a >= 0 && a <= 90));
  137.             l->spot_cutoff = a;
  138.             if(a != 180) {
  139.                 l->cos_spot_cutoff = cos(a * M_PI / 180.0);
  140.             }
  141.         }
  142.         break;
  143.     case GL_CONSTANT_ATTENUATION:
  144.         l->attenuation[0] = v.v[0];
  145.         break;
  146.     case GL_LINEAR_ATTENUATION:
  147.         l->attenuation[1] = v.v[0];
  148.         break;
  149.     case GL_QUADRATIC_ATTENUATION:
  150.         l->attenuation[2] = v.v[0];
  151.         break;
  152.     default:
  153.         assert(0);
  154.     }
  155. }
  156.  
  157. /* */
  158. void glopLightModel(GLContext *c, GLParam *p) {
  159.     int        pname = p[1].i;
  160.     float    *v = &p[2].f;
  161.     int        i;
  162.  
  163.     switch(pname) {
  164.     case GL_LIGHT_MODEL_AMBIENT:
  165.         for(i = 0; i < 4; i++) {
  166.             c->ambient_light_model.v[i] = v[i];
  167.         }
  168.         break;
  169.     case GL_LIGHT_MODEL_LOCAL_VIEWER:
  170.         c->local_light_model = (int) v[0];
  171.         break;
  172.     case GL_LIGHT_MODEL_TWO_SIDE:
  173.         c->light_model_two_side = (int) v[0];
  174.         break;
  175.     default:
  176.         tgl_warning("glopLightModel: illegal pname: 0x%x\n", pname);
  177.  
  178.         /* assert(0); */
  179.         break;
  180.     }
  181. }
  182.  
  183. /* */
  184. static inline float clampf(float a, float min, float max) {
  185.     if(a < min) {
  186.         return min;
  187.     }
  188.     else if(a > max) {
  189.         return max;
  190.     }
  191.     else {
  192.         return a;
  193.     }
  194. }
  195.  
  196. /* */
  197. void gl_enable_disable_light(GLContext *c, int light, int v) {
  198.     GLLight *l = &c->lights[light];
  199.     if(v && !l->enabled) {
  200.         l->enabled = 1;
  201.         l->next = c->first_light;
  202.         c->first_light = l;
  203.         l->prev = NULL;
  204.     }
  205.     else if(!v && l->enabled) {
  206.         l->enabled = 0;
  207.         if(l->prev == NULL) {
  208.             c->first_light = l->next;
  209.         }
  210.         else {
  211.             l->prev->next = l->next;
  212.         }
  213.  
  214.         if(l->next != NULL) {
  215.             l->next->prev = l->prev;
  216.         }
  217.     }
  218. }
  219.  
  220. /* non optimized lightening model */
  221. void gl_shade_vertex(GLContext *c, GLVertex *v) {
  222.     float        R, G, B, A;
  223.     GLMaterial    *m;
  224.     GLLight        *l;
  225.     V3            n, s, d;
  226.     float        dist, tmp, att, dot, dot_spot, dot_spec;
  227.     int            twoside = c->light_model_two_side;
  228.  
  229.     m = &c->materials[0];
  230.  
  231.     n.X = v->normal.X;
  232.     n.Y = v->normal.Y;
  233.     n.Z = v->normal.Z;
  234.  
  235.     R = m->emission.v[0] + m->ambient.v[0] * c->ambient_light_model.v[0];
  236.     G = m->emission.v[1] + m->ambient.v[1] * c->ambient_light_model.v[1];
  237.     B = m->emission.v[2] + m->ambient.v[2] * c->ambient_light_model.v[2];
  238.     A = clampf(m->diffuse.v[3], 0, 1);
  239.  
  240.     for(l = c->first_light; l != NULL; l = l->next) {
  241.         float    lR, lB, lG;
  242.  
  243.         /* ambient */
  244.         lR = l->ambient.v[0] * m->ambient.v[0];
  245.         lG = l->ambient.v[1] * m->ambient.v[1];
  246.         lB = l->ambient.v[2] * m->ambient.v[2];
  247.  
  248.         if(l->position.v[3] == 0) {
  249.             /* light at infinity */
  250.             d.X = l->position.v[0];
  251.             d.Y = l->position.v[1];
  252.             d.Z = l->position.v[2];
  253.             att = 1;
  254.         }
  255.         else {
  256.             /* distance attenuation */
  257.             d.X = l->position.v[0] - v->ec.v[0];
  258.             d.Y = l->position.v[1] - v->ec.v[1];
  259.             d.Z = l->position.v[2] - v->ec.v[2];
  260.             dist = sqrt(d.X * d.X + d.Y * d.Y + d.Z * d.Z);
  261.             if(dist > 1E-3) {
  262.                 tmp = 1 / dist;
  263.                 d.X *= tmp;
  264.                 d.Y *= tmp;
  265.                 d.Z *= tmp;
  266.             }
  267.  
  268.             att = 1.0f / (l->attenuation[0] + dist * (l->attenuation[1] + dist * l->attenuation[2]));
  269.         }
  270.  
  271.         dot = d.X * n.X + d.Y * n.Y + d.Z * n.Z;
  272.         if(twoside && dot < 0) {
  273.             dot = -dot;
  274.         }
  275.  
  276.         if(dot > 0) {
  277.             /* diffuse light */
  278.             lR += dot * l->diffuse.v[0] * m->diffuse.v[0];
  279.             lG += dot * l->diffuse.v[1] * m->diffuse.v[1];
  280.             lB += dot * l->diffuse.v[2] * m->diffuse.v[2];
  281.  
  282.             /* spot light */
  283.             if(l->spot_cutoff != 180) {
  284.                 dot_spot = -
  285.                     (
  286.                         d.X *
  287.                         l->norm_spot_direction.v[0] +
  288.                         d.Y *
  289.                         l->norm_spot_direction.v[1] +
  290.                         d.Z *
  291.                         l->norm_spot_direction.v[2]
  292.                     );
  293.                 if(twoside && dot_spot < 0) {
  294.                     dot_spot = -dot_spot;
  295.                 }
  296.  
  297.                 if(dot_spot < l->cos_spot_cutoff) {
  298.                     /* no contribution */
  299.                     continue;
  300.                 }
  301.                 else {
  302.                     /* TODO: optimize */
  303.                     if(l->spot_exponent > 0) {
  304.                         att = att * pow(dot_spot, l->spot_exponent);
  305.                     }
  306.                 }
  307.             }
  308.  
  309.             /* specular light */
  310.             if(c->local_light_model) {
  311.                 V3    vcoord;
  312.                 vcoord.X = v->ec.X;
  313.                 vcoord.Y = v->ec.Y;
  314.                 vcoord.Z = v->ec.Z;
  315.                 gl_V3_Norm(&vcoord);
  316.                 s.X = d.X - vcoord.X;
  317.                 s.Y = d.Y - vcoord.X;
  318.                 s.Z = d.Z - vcoord.X;
  319.             }
  320.             else {
  321.                 s.X = d.X;
  322.                 s.Y = d.Y;
  323.                 s.Z = d.Z + 1.0;
  324.             }
  325.  
  326.             dot_spec = n.X * s.X + n.Y * s.Y + n.Z * s.Z;
  327.             if(twoside && dot_spec < 0) {
  328.                 dot_spec = -dot_spec;
  329.             }
  330.  
  331.             if(dot_spec > 0) {
  332.                 GLSpecBuf    *specbuf;
  333.                 int            idx;
  334.                 tmp = sqrt(s.X * s.X + s.Y * s.Y + s.Z * s.Z);
  335.                 if(tmp > 1E-3) {
  336.                     dot_spec = dot_spec / tmp;
  337.                 }
  338.  
  339.                 /*
  340.                  * TODO: optimize £
  341.                  * testing specular buffer code £
  342.                  * dot_spec= pow(dot_spec,m->shininess);
  343.                  */
  344.                 specbuf = specbuf_get_buffer(c, m->shininess_i, m->shininess);
  345.                 idx = (int) (dot_spec * SPECULAR_BUFFER_SIZE);
  346.                 if(idx > SPECULAR_BUFFER_SIZE) {
  347.                     idx = SPECULAR_BUFFER_SIZE;
  348.                 }
  349.  
  350.                 dot_spec = specbuf->buf[idx];
  351.                 lR += dot_spec * l->specular.v[0] * m->specular.v[0];
  352.                 lG += dot_spec * l->specular.v[1] * m->specular.v[1];
  353.                 lB += dot_spec * l->specular.v[2] * m->specular.v[2];
  354.             }
  355.         }
  356.  
  357.         R += att * lR;
  358.         G += att * lG;
  359.         B += att * lB;
  360.     }
  361.  
  362.     v->color.v[0] = clampf(R, 0, 1);
  363.     v->color.v[1] = clampf(G, 0, 1);
  364.     v->color.v[2] = clampf(B, 0, 1);
  365.     v->color.v[3] = A;
  366. }
  367.